package com.example.demo.algorithm.delay_queue;

import org.springframework.context.annotation.Bean;

import java.util.Queue;

public class RabbitMqQueue {
    /**
     * RabbitMQ 延时队列
     * 利用 RabbitMQ 做延时队列是比较常见的一种方式，而实际上RabbitMQ 自身并没有直接支持提供延迟队列功能，而是通过 RabbitMQ 消息队列的 TTL和 DXL这两个属性间接实现的。
     *
     * 先来认识一下 TTL和 DXL两个概念：
     *
     * Time To Live(TTL) ：
     *
     * TTL 顾名思义：指的是消息的存活时间，RabbitMQ可以通过x-message-tt参数来设置指定Queue（队列）和 Message（消息）上消息的存活时间，它的值是一个非负整数，单位为微秒。
     *
     * RabbitMQ 可以从两种维度设置消息过期时间，分别是队列和消息本身
     *
     * 设置队列过期时间，那么队列中所有消息都具有相同的过期时间。
     * 设置消息过期时间，对队列中的某一条消息设置过期时间，每条消息TTL都可以不同。
     * 如果同时设置队列和队列中消息的TTL，则TTL值以两者中较小的值为准。而队列中的消息存在队列中的时间，一旦超过TTL过期时间则成为Dead Letter（死信）。
     *
     * Dead Letter Exchanges（DLX）
     *
     * DLX即死信交换机，绑定在死信交换机上的即死信队列。RabbitMQ的 Queue（队列）可以配置两个参数x-dead-letter-exchange 和 x-dead-letter-routing-key（可选），一旦队列内出现了Dead Letter（死信），则按照这两个参数可以将消息重新路由到另一个Exchange（交换机），让消息重新被消费。
     *
     * x-dead-letter-exchange：队列中出现Dead Letter后将Dead Letter重新路由转发到指定 exchange（交换机）。
     *
     * x-dead-letter-routing-key：指定routing-key发送，一般为要指定转发的队列。
     *
     * 队列出现Dead Letter的情况有：
     *
     * 消息或者队列的TTL过期
     * 队列达到最大长度
     * 消息被消费端拒绝（basic.reject or basic.nack）
     * 下边结合一张图看看如何实现超30分钟未支付关单功能，我们将订单消息A0001发送到延迟队列order.delay.queue，并设置x-message-tt消息存活时间为30分钟，当到达30分钟后订单消息A0001成为了Dead Letter（死信），延迟队列检测到有死信，通过配置x-dead-letter-exchange，将死信重新转发到能正常消费的关单队列，直接监听关单队列处理关单逻辑即可。
     */

    //发送消息时指定消息延迟的时间
//    public void send(String delayTimes) {
//        amqpTemplate.convertAndSend("order.pay.exchange", "order.pay.queue","大家好我是延迟数据", message -> {
//            // 设置延迟毫秒值
//            message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
//            return message;
//        });
//    }


//    设置延迟队列出现死信后的转发规则
    /**
     * 延时队列
     */
//    @Bean(name = "order.delay.queue")
//    public Queue getMessageQueue() {
//        return QueueBuilder
//                .durable(RabbitConstant.DEAD_LETTER_QUEUE)
//                // 配置到期后转发的交换
//                .withArgument("x-dead-letter-exchange", "order.close.exchange")
//                // 配置到期后转发的路由键
//                .withArgument("x-dead-letter-routing-key", "order.close.queue")
//                .build();
//    }
}
